# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from django.core.paginator import Paginator
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import redirect
from horizon import views
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.instances \
    import utils as instance_utils
from openstack_dashboard.dashboards.project.images \
    import utils as image_utils
from horizon import exceptions
from django.utils.text import normalize_newlines
import copy
from cloudkittydashboard.api import cloudkitty as cloudkitty_api
from collections import OrderedDict
import calendar
import collections
import datetime
import decimal
import time

total_context = {}


class BaseView(views.APIView):
    def __init__(self):
        super().__init__()
        self.context = {}


class BasicSettingView(BaseView):
    # A very simple class-based view...
    template_name = 'ratingfunction/billing/basic_setting.html'

    def get_service_id(self):
        """
               [{'id': '5b6b6526-9e98-4254-8130-e1957986bcc0', 'name': 'disk.root.size'},
               {'id': '66b0849f-1d81-49bd-924f-4b5f63cac94c', 'name': 'image.size'},
               {'id': '0cbb246f-6c49-46bf-b82e-1b089800663b', 'name': 'instance'},
               {'id': '687f9a63-4b28-4337-8769-59d049303e40', 'name': 'ip.floating'},
               {'id': '3d91b136-78b0-43bf-8115-d579ada8e93e', 'name': 'memory'},
                {'id': 'ed39dd2a-1464-4298-acb5-06c63e5d91ad', 'name': 'network.incoming.bytes'},
                {'id': '030e1a33-6ca5-4ed7-9b71-6c3ea3fef731', 'name': 'network.incoming.bytes.rate'},
                {'id': '41144bdc-a04c-4cd5-9d4e-d92f94d8c5c5', 'name': 'network.outgoing.bytes'},
                {'id': 'b88a91cc-6d27-440a-8fe1-225fd900862f', 'name': 'network.outgoing.bytes.rate'},
                {'id': 'd56aadb0-bdc7-482e-8495-9b2ad4634e94', 'name': 'radosgw.objects.size'},
                {'id': '0cf45217-7043-42b4-a2ef-b72e486c27f2', 'name': 'vcpus'},
               {'id': 'ed46e900-af4f-4d46-ae0e-6b5542383b4e', 'name': 'volume.size'}]
               """
        manager = cloudkitty_api.cloudkittyclient(self.request)
        services = manager.rating.hashmap.get_service().get('services', [])
        services = sorted(services, key=lambda service: service['name'])
        list_services = []
        for s in services:
            list_services.append({
                "id": s['service_id'],
                "name": s['name'],
            })
        """
        [{'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'name': 'flavor_id', 'service_id': '0cbb246f-6c49-46bf-b82e-1b089800663b', 'id': '6690992f-5be2-4d3f-a6e9-545161fcf78a'},
        {'field_id': '22fdcb03-2025-43e9-a24a-b9c2029311b9', 'name': 'vcpus', 'service_id': '0cbb246f-6c49-46bf-b82e-1b089800663b', 'id': '22fdcb03-2025-43e9-a24a-b9c2029311b9'}]
        """
        return list_services

    def get_fields_data(self, request):
        get_service_id = self.get_service_id()
        service_id = []
        for obj in get_service_id:
            if obj["name"] == "instance":
                id = obj["id"]
                service_id.append(id)

        client = cloudkitty_api.cloudkittyclient(request)
        fields = client.rating.hashmap.get_field(
            service_id=service_id[0])['fields']
        return cloudkitty_api.identify(fields, key='field_id')

    def add_groupname(self, request, datums):
        client = cloudkitty_api.cloudkittyclient(request)
        groups = client.rating.hashmap.get_group().get('groups', [])
        full_groups = OrderedDict([(str(group['group_id']), group['name'])
                                   for group in groups])

        for datum in datums:
            if datum.get('group_id'):
                if datum['group_id'] in full_groups:
                    datum['group_name'] = full_groups[datum['group_id']]
                else:
                    group = client.rating.hashmap.get_group(
                        group_id=datum['group_id'])
                    datum['group_name'] = group['name']

    def get_mappings_data(self, request):

        get_fields_data = self.get_fields_data(request)
        field_id = []
        for obj in get_fields_data:
            if obj["name"] == "flavor_id":
                id = obj["field_id"]
                field_id.append(id)
        client = cloudkitty_api.cloudkittyclient(request)
        mappings = client.rating.hashmap.get_mapping(
            field_id=field_id[0]).get('mappings', [])
        self.add_groupname(request, mappings)
        """
       [{'mapping_id': '12e85dbb-0345-409a-9352-46efc517c814', 'value': '42', 'type': 'flat', 'cost': '1.0000000000000000000000000000', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '12e85dbb-0345-409a-9352-46efc517c814', 'name': '12e85dbb-0345-409a-9352-46efc517c814'}, 
       {'mapping_id': 'e1922100-b173-46de-8130-a7aee12929ec', 'value': '84', 'type': 'flat', 'cost': '2.0000000000000000000000000000', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'e1922100-b173-46de-8130-a7aee12929ec', 'name': 'e1922100-b173-46de-8130-a7aee12929ec'},
        {'mapping_id': '75b3e2df-f81b-4db8-9989-39b9988cd75e', 'value': 'c1', 'type': 'flat', 'cost': '3.0000000000000000000000000000', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '75b3e2df-f81b-4db8-9989-39b9988cd75e', 'name': '75b3e2df-f81b-4db8-9989-39b9988cd75e'},
        {'mapping_id': '3e8b504b-ca26-467b-ba84-f39102750b70', 'value': 'd4', 'type': 'flat', 'cost': '1.4799999999999999822364316060', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '3e8b504b-ca26-467b-ba84-f39102750b70', 'name': '3e8b504b-ca26-467b-ba84-f39102750b70'}, 
        {'mapping_id': 'c7e0e570-e70c-416e-8cec-4c03666b26ee', 'value': 'd2', 'type': 'flat', 'cost': '0.3699999999999999955591079015', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'c7e0e570-e70c-416e-8cec-4c03666b26ee', 'name': 'c7e0e570-e70c-416e-8cec-4c03666b26ee'}, 
        {'mapping_id': '4cca2d96-c589-4327-b01e-590e9d629a42', 'value': 'd3', 'type': 'flat', 'cost': '0.7399999999999999911182158030', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '4cca2d96-c589-4327-b01e-590e9d629a42', 'name': '4cca2d96-c589-4327-b01e-590e9d629a42'},
         {'mapping_id': '90852c3e-6bfd-4c74-a420-05a96ae99a00', 'value': 'd1', 'type': 'flat', 'cost': '0.1799999999999999933386618522', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '90852c3e-6bfd-4c74-a420-05a96ae99a00', 'name': '90852c3e-6bfd-4c74-a420-05a96ae99a00'}, 
         {'mapping_id': 'dbd9811a-eb47-4195-b274-62809debff61', 'value': '4', 'type': 'flat', 'cost': '1.4799999999999999822364316060', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'dbd9811a-eb47-4195-b274-62809debff61', 'name': 'dbd9811a-eb47-4195-b274-62809debff61'}, 
         {'mapping_id': 'af1e9de1-adb3-4057-b907-a6411631c049', 'value': '3', 'type': 'flat', 'cost': '0.7399999999999999911182158030', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'af1e9de1-adb3-4057-b907-a6411631c049', 'name': 'af1e9de1-adb3-4057-b907-a6411631c049'}, 
         {'mapping_id': 'cb889a35-f85b-4592-aa26-5e2d2ddda7d7', 'value': '2', 'type': 'flat', 'cost': '0.3699999999999999955591079015', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'cb889a35-f85b-4592-aa26-5e2d2ddda7d7', 'name': 'cb889a35-f85b-4592-aa26-5e2d2ddda7d7'}, 
         {'mapping_id': '926b0ae7-1327-4ac4-b74c-f0c13f3250be', 'value': '1', 'type': 'flat', 'cost': '0.1799999999999999933386618522', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': '926b0ae7-1327-4ac4-b74c-f0c13f3250be', 'name': '926b0ae7-1327-4ac4-b74c-f0c13f3250be'}, 
         {'mapping_id': 'e34d4bac-0665-4914-b55b-b93eb48e83dd', 'value': '5', 'type': 'flat', 'cost': '1.4799999999999999822364316060', 'service_id': None, 'field_id': '6690992f-5be2-4d3f-a6e9-545161fcf78a', 'group_id': None, 'tenant_id': None, 'id': 'e34d4bac-0665-4914-b55b-b93eb48e83dd', 'name': 'e34d4bac-0665-4914-b55b-b93eb48e83dd'}]
        """
        return cloudkitty_api.identify(mappings, key='mapping_id', name=True)

    def _get_flavor_list(self, request):
        get_mappings_data = self.get_mappings_data(request)  # 获取每个规格的价格字典数据
        map_list = []  # 计费映射列表
        for m in get_mappings_data:
            map_list.append(m["value"])

        flavors_list = []
        flavors = api.nova.flavor_list(request)
        for obj in flavors:
            for map in get_mappings_data:
                if map["value"] == obj.id:  # 判断flavor的id,如果和计费中的value相同，就把cost放到flavors_dict中
                    flavors_dict = {
                        "name": obj.name,
                        "id": obj.id,
                        "memory_mb": obj.ram,
                        "vcpus": obj.vcpus,
                        "disk": obj.disk,
                        "is_public": obj.is_public,
                        "cost": map["cost"]
                    }
                    flavors_list.append(flavors_dict)
                elif obj.id not in map_list:  # 如果flavor的id没在在计费映射列表里面，就把cost放到flavors_dict字典里cost置为0
                    flavors_dict = {
                        "name": obj.name,
                        "id": obj.id,
                        "memory_mb": obj.ram,
                        "vcpus": obj.vcpus,
                        "disk": obj.disk,
                        "is_public": obj.is_public,
                        "cost": 0
                    }
                    flavors_list.append(flavors_dict)
                    break
        return flavors_list

    def get_data(self, request, context, *args, **kwargs):
        # Add data to the context here...
        template_title = "basic_setting"
        button_title = "下一步，网络配置"
        zones = api.nova.availability_zone_list(request)
        zone_list = [zone.zoneName
                     for zone in zones if zone.zoneState['available']]
        zone_list.sort()

        self._images_cache = {}
        images_list = image_utils.get_available_images(request,
                                                       context.get('project_id'),
                                                       self._images_cache)
        source_type_choices = [
            {"source_type": "image_id", "name": _("Image"), "obj_list": images_list,
             "description": _("Boot from image")},
            {"source_type": "instance_snapshot_id", "name": _("Instance Snapshot"), "obj_list": "",
             "description": _("Boot from snapshot")},
            {"source_type": "volume_id", "name": _("Volume"), "obj_list": "", "description": _("Boot from volume")},
            {"source_type": "volume_image_id", "name": _("Volume Image"), "obj_list": "",
             "description": _("Boot from image (creates a new volume)")},
            {"source_type": "volume_snapshot_id", "name": _("Volume Snapshot"), "obj_list": "",
             "description": _("Boot from volume snapshot (creates a new volume)")},
        ]
        flavors_list = self._get_flavor_list(request)
        context = {"nova_list": zone_list,
                   "flavor_list": flavors_list,
                   "source_type_choices": source_type_choices,
                   "template_title": template_title,
                   "button_title": button_title,
                   }
        total_context["flavors_list"] = flavors_list
        total_context["images_list"] = images_list
        total_context["source_type_choices"] = source_type_choices
        return context

    def post(self, request):
        flavor_id = request.POST.get("flavor_id")
        source_type = request.POST.get("source_type")
        image_id = request.POST.get("image_id")
        availability_zone = request.POST.get("availability_zone")
        volume_size = request.POST.get("volume_size")
        instance_count = request.POST.get("instance_count")
        single_money = request.POST.get("single_money")
        self.context["single_money"] = float(single_money)
        self.context["instance_count"] = int(instance_count)
        self.context["source_type"] = source_type
        self.context["flavor_id"] = flavor_id
        self.context["image_id"] = image_id
        self.context["availability_zone"] = availability_zone
        self.context["volume_size"] = volume_size
        total_context.update(self.context)

        return redirect("horizon:ratingfunction:billing:network_setting")


class NetworkSettingView(BaseView):
    template_name = "ratingfunction/billing/network_setting.html"

    def get_data(self, request, context, *args, **kwargs):
        button_title = "下一步，高级设置"
        try:
            tenant_id = self.request.user.tenant_id
            networks_list = api.neutron.network_list_for_tenant(
                self.request, tenant_id,
                include_external=True,
                include_pre_auto_allocate=True, )
            ports_list = instance_utils.port_field_data(request)
        except Exception:
            ports_list = []
            networks_list = []
        data = copy.deepcopy(total_context)
        context = {"button_title": button_title,
                   "networks_list": networks_list,
                   "ports_list": ports_list,
                   "total_context": data,
                   }
        try:
            context["total_money"] = data["single_money"] * data["instance_count"]
        except Exception:
            context["total_money"] = 0
        total_context["networks_list"] = networks_list
        total_context["ports_list"] = ports_list
        return context

    def post(self, request):
        net_id = request.POST.getlist("network_id")
        network_port = request.POST.get("network_port")
        instance_count = request.POST.get("instance_count")
        create_volume_default = request.POST.get("create_volume_default")  # 创建新卷
        vol_delete_on_instance_delete = request.POST.get("vol_delete_on_instance_delete")  # 创建实例时删除卷
        self.context["instance_count"] = int(instance_count)
        self.context["net_id"] = net_id
        self.context["create_volume_default"] = create_volume_default
        self.context["vol_delete_on_instance_delete"] = vol_delete_on_instance_delete
        self.context["network_port"] = network_port
        total_context.update(self.context)

        return redirect("horizon:ratingfunction:billing:advanced_setting")


class AdvanceSettingView(BaseView):
    template_name = "ratingfunction/billing/advanced_setting.html"

    def clean_uploaded_files(self, prefix, files):
        upload_str = prefix + "_upload"

        if upload_str not in files:
            return None

        upload_file = files[upload_str]
        script = upload_file.read()
        if script != "":
            try:
                if not isinstance(script, str):
                    script = script.decode()
                normalize_newlines(script)
            except Exception as e:
                pass
        return script

    def _script_data(self, request):
        files = request.FILES
        script_data = self.clean_uploaded_files("script", files)
        return script_data

    def get_data(self, request, context, *args, **kwargs):
        button_title = "下一步，确认设置"

        try:
            projects = request.user.tenant_name  # 项目名称（登录用户名）
            security_groups_list = api.neutron.security_group_list(request)  # 安全组
            keypairs_list = api.nova.keypair_list(request)  # 密钥对
        except Exception:
            projects = []
            security_groups_list = []
            keypairs_list = []
        data = copy.deepcopy(total_context)
        context = {"projects": projects,
                   "keypairs": keypairs_list,
                   "groups_list": security_groups_list,
                   "button_title": button_title,
                   "total_context": data
                   }
        try:
            context["total_money"] = data["single_money"] * data["instance_count"]
        except Exception:
            context["total_money"] = 0
        total_context["security_groups_list"] = security_groups_list
        total_context["keypairs_list"] = keypairs_list
        return context

    def post(self, request):
        instance_name = request.POST.get("instance_name")
        admin_password = request.POST.get("password")
        security_group_ids = request.POST.getlist("security_group_id")
        keypairs_id = request.POST.getlist("keypairs")
        config_drive = request.POST.get("config_drive")
        disk_config = request.POST.get("disk_config")
        script_data = self._script_data(request)
        instance_count = request.POST.get("instance_count")
        self.context["instance_count"] = int(instance_count)
        self.context["instance_name"] = instance_name
        self.context["admin_password"] = admin_password
        self.context["security_group_ids"] = security_group_ids
        self.context["keypair_id"] = keypairs_id
        self.context["script_data"] = script_data
        self.context["config_drive"] = config_drive
        self.context["disk_config"] = disk_config
        total_context.update(self.context)
        return redirect("horizon:ratingfunction:billing:confirm_setting")


class ConfirmSettingView(BaseView):
    template_name = "ratingfunction/billing/confirm_setting.html"

    def get_data(self, request, context, *args, **kwargs):
        button_title = "立即购买"
        data = copy.deepcopy(total_context)
        context = {
            "button_title": button_title,
            "total_context": data,
        }
        try:
            context["total_money"] = data["single_money"] * data["instance_count"]
        except Exception:
            context["total_money"] = 0
        return context

    def post(self, request):
        instance_count = request.POST.get("instance_count")
        self.context["instance_count"] = int(instance_count)
        total_context.update(self.context)
        self.handle(request, total_context)
        return redirect("horizon:project:instances:index")

    def handle(self, request, context):
        """
        """
        print(context)
        custom_script = context.get('script_data', '')
        dev_mapping_1 = None
        dev_mapping_2 = None

        image_id = ""
        # Determine volume mapping options
        source_type = context.get('source_type', None)
        if source_type in ['image_id', 'instance_snapshot_id']:
            image_id = context['image_id']
        elif source_type in ['volume_id', 'volume_snapshot_id']:
            # Volume source id is extracted from the source
            volume_source_id = context['source_id'].split(':')[0]
            device_name = context.get('device_name', '').strip() or None
            dev_source_type_mapping = {
                'volume_id': 'volume',
                'volume_snapshot_id': 'snapshot'
            }
            dev_mapping_2 = [
                {'device_name': device_name,
                 'source_type': dev_source_type_mapping[source_type],
                 'destination_type': 'volume',
                 'delete_on_termination':
                     bool(context['vol_delete_on_instance_delete']),
                 'uuid': volume_source_id,
                 'boot_index': '0',
                 'volume_size': context['volume_size']
                 }
            ]
        elif source_type == 'volume_image_id':
            device_name = context.get('device_name', '').strip() or None
            dev_mapping_2 = [
                {'device_name': device_name,  # None auto-selects device
                 'source_type': 'image',
                 'destination_type': 'volume',
                 'delete_on_termination':
                     bool(context['vol_delete_on_instance_delete']),
                 'uuid': context['source_id'],
                 'boot_index': '0',
                 'volume_size': context['volume_size']
                 }
            ]

        netids = context.get('net_id', None)
        if netids:
            nics = [{"net-id": netid, "v4-fixed-ip": ""}
                    for netid in netids]
        else:
            nics = None

        availability_zone = context.get('availability_zone', None)
        instance_name = context.get("instance_name", "-")
        instance_count = context.get("instance_count", 1)
        scheduler_hints = {}
        server_group = context.get('server_group', None)
        if server_group:
            scheduler_hints['group'] = server_group

        ports = context.get('network_port')
        if ports:
            if nics is None:
                nics = []
            nics.extend([{'port-id': port} for port in ports])

        try:
            api.nova.server_create(request,
                                   instance_name,
                                   image_id,
                                   context['flavor_id'],
                                   context['keypair_id'],
                                   normalize_newlines(custom_script),
                                   context['security_group_ids'],
                                   block_device_mapping=dev_mapping_1,
                                   block_device_mapping_v2=dev_mapping_2,
                                   nics=nics,
                                   availability_zone=availability_zone,
                                   instance_count=int(instance_count),
                                   admin_pass=context['admin_password'],
                                   disk_config=context.get('disk_config'),
                                   config_drive=context.get('config_drive'),
                                   scheduler_hints=scheduler_hints)
            return True
        except Exception:
            exceptions.handle(request)
        return False


class CostCenterView(BaseView):
    template_name = "ratingfunction/billing/cost_center.html"

    def _do_init_data(self, data):
        services = {}
        # 这些变量将跟踪用来填充字典的时间跨度
        start_timestamp = None
        end_timestamp = None
        for dataframe in data.get('dataframes', []):
            begin = dataframe['begin']
            timestamp = int(time.mktime(
                datetime.datetime.strptime(begin[:16],
                                           "%Y-%m-%dT%H:%M").timetuple()))
            if start_timestamp is None or timestamp < start_timestamp:
                start_timestamp = timestamp
            if end_timestamp is None or timestamp > end_timestamp:
                end_timestamp = timestamp

            for resource in dataframe['resources']:
                service_id = resource['service']
                service_data = services.setdefault(
                    service_id, {'cumulated': 0, 'hourly': {}})
                service_data['cumulated'] += decimal.Decimal(resource['rating'])
                hourly_data = service_data['hourly']
                hourly_data.setdefault(timestamp, 0)
                hourly_data[timestamp] += float(resource['rating'])

        service_names = services.keys()
        t = start_timestamp
        if end_timestamp:
            while t <= end_timestamp:
                for service in service_names:
                    hourly_d = services[service]['hourly']
                    hourly_d.setdefault(t, 0)
                t += 3600

        # 给字典排序
        for service in service_names:
            d = services[service]['hourly']
            services[service]['hourly'] = collections.OrderedDict(
                sorted(d.items(), key=lambda t: t[0]))

        # 开始处理从接口里面取出的数据
        dict_list = []
        for i, j in services.items():
            dic = {}
            dic["name"] = i
            ls = []
            for hour, cost in j["hourly"].items():
                d = {}
                d["hour"] = hour
                d["cost"] = cost
                ls.append(d)
                dic["data"] = ls
            dict_list.append(dic)
        return dict_list

    def _get_product_data(self, dict_list, request):
        """得到同一时间产品类型的计费数据"""
        projects = request.user.tenant_name  # 项目名称（登录用户名）
        # 获取时间列表 ， 用于后面提取数据
        hour_list = []
        for obj in dict_list:
            for i in obj["data"]:
                hour_list.append(i["hour"])
            break
        # 将产品类型、时间、计费放到同一个字典里
        lis = []
        for obj in dict_list:
            for dic in obj["data"]:
                dic["name"] = obj["name"]
                dic["projects"] = projects
                dic["date"] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(dic["hour"]))
                lis.append(dic)

        # 将产品类型根据相同时间放在同一个列表里
        total_list = []
        for i in hour_list:
            lis_ = []
            for j in lis:
                if i == j["hour"]:
                    lis_.append(j)
            total_list.extend(lis_)
        return total_list

    def _page_data(self, request, project_cost_list):
        """处理分页数据"""
        paginator = Paginator(project_cost_list, 12)  # 实例化分页对象,每页12分数据
        total_page_num = paginator.num_pages  # 总页码
        current_page_num = int(self.kwargs["page"])  # 当前页，默认显示第一页
        page_data = paginator.page(current_page_num)
        page_range = paginator.page_range  # 确定页面范围，以便进行模板渲染使用页码
        # 当前页
        if total_page_num > 5:  # 当总页码大于5时
            if current_page_num < 4:  # 当前页小于4时,页码范围是（1,5）
                page_range = range(1, 6)
            elif current_page_num + 3 > total_page_num:  # 当前页码是倒数第3页时
                page_range = range(current_page_num - 2, total_page_num + 1)
            else:
                page_range = range(current_page_num - 2, current_page_num + 3)
        return page_data, page_range, current_page_num, total_page_num

    def get_data(self, request, context, *args, **kwargs):
        today = datetime.datetime.today()
        day_start, day_end = calendar.monthrange(today.year, today.month)
        begin = "1970-01-01T00:00:00"
        end = "%4d-%02d-%02dT23:59:59" % (today.year, today.month, day_end)
        client = cloudkitty_api.cloudkittyclient(request)
        data = client.storage.get_dataframes(
            begin=begin, end=end, tenant_id=request.user.tenant_id)
        dict_list = self._do_init_data(data)
        # 得到同一时间产品类型的计费数据
        project_cost_list = self._get_product_data(dict_list, request)
        # 处理分页数据
        page_data, page_range, current_page_num, total_page_num = self._page_data(request, project_cost_list)
        context = {
            "page_data": page_data,
            "page_range": page_range,
            "current_page_num": current_page_num,
            "total_page_num": total_page_num,
        }
        return context
